package com.forgenet.game.module.player.gm.manager;

import com.forgenet.game.module.player.Player;
import com.forgenet.game.module.player.gm.anno.GM;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.sparrow.common.console.domain.ConsoleCommandWrapper;
import com.sparrow.common.util.PropertiesUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.convert.ConversionService;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;

import java.util.Map;

@Component
public class GMManager implements BeanPostProcessor {

    @Autowired
    private ConversionService conversionService;

    private static volatile int open = PropertiesUtil.autoReloadInt("gm.open", (val) -> open = val, 0);

    private final Map<String, ConsoleCommandWrapper> wrapperMap = Maps.newHashMap();

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        register(bean);
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }

    public void register(Object target) {
        ReflectionUtils.doWithMethods(target.getClass(), method -> {
            GM annotation = method.getAnnotation(GM.class);
            ConsoleCommandWrapper pre = wrapperMap.putIfAbsent(annotation.cmd(), new ConsoleCommandWrapper(target, method, conversionService));
            Preconditions.checkState(pre == null, annotation.cmd() + " 重复注册!");
        }, method -> method.isAnnotationPresent(GM.class));
    }

    /**
     * 使用命令
     * @param command
     * @return
     */
    public boolean useCommand(Player player, String command) {
        if (!isOpen()) {
            throw new IllegalStateException("管理员命令未开启");
        }
        String[] split = command.split("\\s");
        ConsoleCommandWrapper wrapper = wrapperMap.get(split[0]);
        if (wrapper == null) {
            return false;
        }

        Object[] arguments = getArguments(player, command);
        wrapper.execute(arguments);
        return true;
    }

    Object[] getArguments(Player player, String line) {
        if (StringUtils.isBlank(line)) {
            return new String[0];
        }
        String[] arguments = StringUtils.split(line);
        if (arguments.length <= 1) {
            return new String[0];
        }
        Object[] result = new Object[arguments.length];
        System.arraycopy(arguments, 1, result, 1, arguments.length - 1);
        result[0] = player;
        return result;
    }

    private boolean isOpen() {
        return open == 1;
    }
}
